package com.nulldev.util.net.experimental.groupedudp.files;

import java.io.File;
import java.io.IOException;

import com.nulldev.util.io.FileUtil;
import com.nulldev.util.net.experimental.groupedudp.AGroupThread;
import com.nulldev.util.net.experimental.groupedudp.Encryptor;
import com.nulldev.util.net.experimental.groupedudp.UDPException;
import com.nulldev.util.net.experimental.groupedudp.datagrams.ADatagram;
import com.nulldev.util.net.experimental.groupedudp.datagrams.files.FileShareBinaryPart;

public class SharedBinaryFile extends ASharedFile {
	private byte[] data;
    private int partsCount;
    /**Maximal length of binary part data according to configuration*/    
    public static int DATA_LENGTH = -1;
    static{
        int infoLength = 32 + ADatagram.DATAGRAM_HEADER.length+1;
        DATA_LENGTH = ADatagram.MAXIMUM_DATAGRAM_LENGTH-infoLength;
        //Encryptor takes only 16
        if(DATA_LENGTH % 16 != 0){ 
            DATA_LENGTH -= DATA_LENGTH % 16;
        }
        //messed up configuration
        if(DATA_LENGTH == 0) DATA_LENGTH = 16;
    }
    /**
     * @param fileToShare Data to share
     * @param name Unique String ID, under which will be file accessible at
     * AGroupNetwork class
     * @param groupThread Thread responsible for sending datagrams to group
     * @param encryptor Class responsible for encrypting file content on network
     * @param deadTime Time, which will server wait after finishing file
     * sharing. At this time client may request resending some of the parts
     * @param listener can be null, object which will be notified about
     * success/fail
     */
    public SharedBinaryFile(File fileToShare, String name, AGroupThread groupThread, Encryptor encryptor, int deadTime, IFileShareListener listener) {
        super(fileToShare, name, groupThread, encryptor, deadTime, listener);
    }

    @Override
    protected void readFile() throws IOException, UDPException {
        File path = fileToShare;

        try {
			data = FileUtil.read(path);
		} catch (Exception e) {
			throw new IOException(e);
		}
                
        partsCount = (int)Math.ceil(data.length/DATA_LENGTH);
    }

    private ADatagram createPartDatagram(int index){
        ADatagram datagram;
        byte[] datagramData;
        
        int datagramStart = index*DATA_LENGTH;
        int datagramLength;
        if(datagramStart+DATA_LENGTH<data.length){
            datagramLength = DATA_LENGTH;
        }else{
            datagramLength = data.length - datagramStart;
        }
        datagramData = new byte[datagramLength];
        System.arraycopy(data, datagramStart, datagramData, 0, datagramLength);
            
        datagram = new FileShareBinaryPart(encryptor, name, datagramData, index, partsCount);
        
        return datagram;
    } 
            
    @Override
    protected void sendPartDatagrams() throws InterruptedException{
        int waitingTime = 5;
        
        for(int i = 0; i <= partsCount; i++){
            groupThread.sendMulticastDatagram(createPartDatagram(i));            
            Thread.sleep(waitingTime);
        }
    }
        
    @Override
    public void partRequest(int index) {
        wasRequest = true;
        groupThread.sendMulticastDatagram(createPartDatagram(index));
    }
    
    /**
     * @param part Datagram part data to be sent
     * @return integrity control number
     */
    public static int getChecksum(byte[] part){
        return part.length;
    }
}
